#include "usk_logservice_impl.h"
#include "usk_logger_impl.h"
#include "cppmicroservices/Bundle.h"

namespace usk {
    namespace core {
        class USKLogserviceImplPrivate {
        public:
            std::shared_ptr<Logger> logger_;
            std::map<std::string,
                std::shared_ptr<Logger> >
            loggers_map_;
            mutable std::mutex mutex_;
        };


        USKLogserviceImpl::USKLogserviceImpl(std::string const &loggerName) {
            d_ = std::make_shared<USKLogserviceImplPrivate>();
            d_->logger_ = getLogger(loggerName);
        }

        std::shared_ptr<Logger>
        USKLogserviceImpl::getLogger(std::string const &name) const {
            std::lock_guard<std::mutex> lock(d_->mutex_);
            const auto iter = d_->loggers_map_.find(name);
            if (iter == d_->loggers_map_.end()) {
                auto logger = std::make_shared<USKLoggerImpl>(name);
                d_->loggers_map_[name] = logger;
                return logger;
            }
            return iter->second;
        }

        std::shared_ptr<Logger>
        USKLogserviceImpl::getLogger(const cppmicroservices::Bundle &bundle,
                                     std::string const &name) const {
            const std::string logger_name = bundle.GetSymbolicName() + "." + name;
            return getLogger(logger_name);
        }

        std::shared_ptr<Logger> USKLogserviceImpl::GetCurrentLogger() const {
            return d_->logger_;
        }

        void USKLogserviceImpl::Log(SeverityLevel level, std::string const &message) {
            auto currLogger = std::atomic_load(&d_->logger_);
            if (!currLogger) {
                return;
            }

            logImpl(level, message);
        }

        void USKLogserviceImpl::Log(SeverityLevel level, std::string const &message,
                                    const std::exception_ptr ex) {
            auto currLogger = std::atomic_load(&d_->logger_);
            if (!currLogger) {
                return;
            }

            logImpl(level, message, ex);
        }

        void USKLogserviceImpl::Log(ServiceReferenceBase const &sr, SeverityLevel level,
                                    std::string const &message) {
            auto currLogger = std::atomic_load(&d_->logger_);
            if (!currLogger) {
                return;
            }

            logImpl(level, message, sr);
        }

        void USKLogserviceImpl::Log(ServiceReferenceBase const &sr, SeverityLevel level,
                                    std::string const &message,
                                    const std::exception_ptr ex) {
            auto currLogger = std::atomic_load(&d_->logger_);
            if (!currLogger) {
                return;
            }

            logImpl(level, message, sr, ex);
        }
    } // namespace core
} // namespace usk
